
package com.buli.util.logger;

import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

public class LoggerUtils {
    private static final Logger log = LoggerFactory.getLogger(LoggerUtils.class);
    private static final Map<String, Marker> MARKER_CACHE = new HashMap();
    private static final Map<String, LogLevel> LOG_LEVEL_MAP = new HashMap();

    public LoggerUtils() {
    }

    public static Marker createMarkerWithLocation(LogLevel level) {
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        StackTraceElement caller = getCallerInfo(stackTrace);
        if (caller != null) {
            String className = caller.getClassName();
            String methodName = caller.getMethodName();
            int lineNumber = caller.getLineNumber();
            String key = "CLASS:" + className + "; METHOD:" + methodName + "; LINE:" + lineNumber;
            if (!MARKER_CACHE.containsKey(key)) {
                Marker marker = MarkerFactory.getMarker("LOCATION-" + level);
                marker.add(MarkerFactory.getMarker("类名: " + className));
                marker.add(MarkerFactory.getMarker("方法名: " + methodName));
                marker.add(MarkerFactory.getMarker("所在行号: " + lineNumber));
                MARKER_CACHE.put(key, marker);
            }

            return (Marker)MARKER_CACHE.get(key);
        } else {
            throw new IllegalStateException("Caller information not found.");
        }
    }

    private static StackTraceElement getCallerInfo(StackTraceElement[] stackTrace) {
        for(int i = 2; i < stackTrace.length; ++i) {
            StackTraceElement element = stackTrace[i];
            if (!element.getClassName().equals(LoggerUtils.class.getName())) {
                return element;
            }
        }

        return null;
    }

    public static void logWithLocation(String message, Object... args) {
        logWithLocation((Object)LoggerUtils.LogLevel.INFO, (String)message, (Object[])args);
    }

    public static void logWithLocation(Object message, Object... args) {
        logWithLocation((Object)LoggerUtils.LogLevel.INFO, (String)message.toString(), (Object[])args);
    }

    public static void logWithLocation(Object level, String message, Object... args) {
        LogLevel logLevel = getLogLevel(level);
        logWithLevel(log, logLevel, message, args);
    }

    public static void logWithLocation(Logger logger, String message) {
        logWithLocation((Logger)logger, (Object)LoggerUtils.LogLevel.INFO, (String)message);
    }

    public static void logWithLocation(Logger logger, Object level, String message) {
        LogLevel logLevel = getLogLevel(level);
        logWithLevel(logger != null ? logger : log, logLevel, message);
    }

    public static void logWithLocation(Logger logger, String message, Object... args) {
        logWithLocation(logger, LoggerUtils.LogLevel.INFO, message, args);
    }

    public static void logWithLocation(Logger logger, Object level, String message, Object... args) {
        LogLevel logLevel = getLogLevel(level);
        logWithLevel(logger != null ? logger : log, logLevel, message, args);
    }

    public static void info(String message, Object... var2) {
        logWithLevel(log, LoggerUtils.LogLevel.INFO, message, var2);
    }

    public static void error(String message, Object... var2) {
        logWithLevel(log, LoggerUtils.LogLevel.ERROR, message, var2);
    }

    public static void debug(String message, Object... var2) {
        logWithLevel(log, LoggerUtils.LogLevel.DEBUG, message, var2);
    }

    public static void warn(String message, Object... var2) {
        logWithLevel(log, LoggerUtils.LogLevel.WARN, message, var2);
    }

    private static LogLevel getLogLevel(Object level) {
        if (level instanceof LogLevel) {
            return (LogLevel)level;
        } else if (level instanceof String) {
            String levelStr = ((String)level).toUpperCase();
            return (LogLevel)LOG_LEVEL_MAP.getOrDefault(levelStr, LoggerUtils.LogLevel.INFO);
        } else {
            throw new IllegalArgumentException("Unsupported log level type: " + level.getClass().getName());
        }
    }

    private static void logWithLevel(Logger logger, LogLevel level, String message, Object... args) {
        Marker marker = createMarkerWithLocation(level);
        switch (level) {
            case INFO:
                logger.info(marker, message, args);
                break;
            case ERROR:
                logger.error(marker, message, args);
                break;
            case DEBUG:
                logger.debug(marker, message, args);
                break;
            case WARN:
                logger.warn(marker, message, args);
        }

    }

    static {
        LOG_LEVEL_MAP.put("INFO", LoggerUtils.LogLevel.INFO);
        LOG_LEVEL_MAP.put("ERROR", LoggerUtils.LogLevel.ERROR);
        LOG_LEVEL_MAP.put("DEBUG", LoggerUtils.LogLevel.DEBUG);
        LOG_LEVEL_MAP.put("WARN", LoggerUtils.LogLevel.WARN);
    }

    public static enum LogLevel {
        INFO,
        ERROR,
        DEBUG,
        WARN;

        private LogLevel() {
        }
    }
}
